test: beasting infra + raise coverage 47%→94%, fix silent watch event-drop bug - #309
Conversation
Adds beast.sh, which builds once then runs the suite N times with --no-build to surface timing/race-driven flakiness in the watch/auth/lease streaming paths. Configurable iterations, category filter (Unit|Integration|All), and stop-on-first vs keep-going. Plus an opt-in beast-tests.yml workflow (manual dispatch + nightly).
…intenance + helpers Adds unit tests covering all unary public methods and overloads (sync + async) across the EtcdClient feature partials via the existing MockConnection/TestHelper pattern, plus AsyncHelper (was 0%), AsyncDuplexStreamingCallAdapter, and EtcdClient core methods (GetConnection/GetWatchManager/CancelWatch/Dispose). +142 unit tests (111 -> 253). Streaming methods (KeepAlive/Observe/Snapshot/Watch) excluded; covered separately.
Collect coverage from the integration test run too; reportgenerator already globs ./coverage/** and merges the cobertura files, so the badge/report now reflects combined unit + integration coverage instead of unit-only.
…treaming coverage Watch(WatchRequest[], Action<WatchEvent[]>[]) and the async variant captured the for-loop variable inside the event-conversion closure, so when an event later arrived the wrapper indexed methods[requests.Length] -> IndexOutOfRangeException on a background task, silently dropping every event. Capture a per-iteration local index. Adds a controllable FakeDuplexStreamingCall plus unit tests for WatchManager, the EtcdClient watch wrappers (incl. delivery tests that fail without the fix), duplex LeaseKeepAlive, server-streaming Observe/Snapshot, and constructor validation. Combined line coverage 46.7% -> 93.8%.
The nightly beast schedule already runs, but per-iteration logs went to an ephemeral mktemp dir lost when the runner tears down. beast.sh now honors BEAST_LOG_DIR; the workflow points it at the workspace and uploads it as an artifact on failure, so a nightly flake is diagnosable.
|
Summary dotnet-etcd 94.4% |
Description
What & why
The test suite was green but shallow — combined coverage sat at 46.7%, most of it from integration tests the CI badge didn't even count, and there was no defense against timing/concurrency flakiness. This PR adds repeat-run "beasting", drives combined coverage to 93.8%, and — as a direct result of writing real delivery tests — uncovers and fixes a production bug that silently dropped watch events.
Beasting (flaky-test detection)
dotnet-etcd.Tests/beast.sh— builds once, then runs the suite N times with--no-buildso only non-determinism can fail a run. Configurable iterations (-n), category (-f Unit|Integration|All), and stop-on-first vs keep-going (-k). HonorsBEAST_LOG_DIR..github/workflows/beast-tests.yml— opt-in CI: manualworkflow_dispatch(iterations/category inputs) and a nightly schedule (cron: '0 4 * * *'). Per-iteration logs upload as an artifact on failure so a nightly flake is reproducible.Coverage: 46.7% → 93.8%
MockConnection/TestHelperpattern.FakeDuplexStreamingCallmock unlocking the streaming paths:WatchManager(25%→93%),Watcher, theEtcdClientwatch wrappers, duplexLeaseKeepAlive, and server-streamingObserve/Snapshot.AsyncHelper(0%→100%),AsyncDuplexStreamingCallAdapter, constructor validation, andEtcdClientcore.Bug fix (TDD)
EtcdClient.Watch(WatchRequest[], Action<WatchEvent[]>[])and its async twin captured thefor-loop variable inside the event-conversion closure. When an event later arrived, the wrapper indexedmethods[requests.Length]→IndexOutOfRangeExceptionon a background task, silently dropping every event. Reproduced with a failing delivery test (a=0, b=0), fixed with a per-iteration local index, confirmed green.